Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Safe Global Predefined Color Palettes #13598

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

Swiftb0y
Copy link
Member

@Swiftb0y Swiftb0y commented Aug 25, 2024

As suggested (by me) in #13594 (comment) as an alternative to that PR.

Note that in case we manage to make ColorPalette constexpr friendly, we can trivially migrate get to be constexpr as well without having to change the callers with this approach.

@@ -109,7 +109,7 @@ int BaseTrackTableModel::s_bpmColumnPrecision =
kBpmColumnPrecisionDefault;
bool BaseTrackTableModel::s_keyColorsEnabled = kKeyColorsEnabledDefault;
ColorPalette BaseTrackTableModel::s_keyColorPalette =
mixxx::PredefinedColorPalettes::kDefaultKeyColorPalette;
mixxx::predefinedcolorpalettes::get().defaultKeyColorPalette;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In #13594 we have an std::optional which makes redundant initialization here obsolete.
Let's mere #13594 first.

@daschuer
Copy link
Member

Did you consider to make PredefinedColorPalettes a singleton? This avoids to initalize it over and over again and will avoid the new predefinedcolorpalettes namespace.

@Swiftb0y
Copy link
Member Author

It is effectively a singleton. It is only getting initialized once. see Static block variables

This will avoid the "static initialization order fiasco" by putting
all palettes behind a C++11 "magic static" that ensure that that
they are initialized before they're first used.
@Swiftb0y Swiftb0y force-pushed the refactor/safe-predefinedcolorpalettes branch from a5b7d98 to 1c7afe6 Compare August 26, 2024 17:49
@Swiftb0y
Copy link
Member Author

fyi, an alternative implementation would be to use const constinit. That works with qt containers (in theory once they make move operations constexpr). Alternatively we can also make ColorPalettes use std::vector and std::string internally. Then we can even constexpr static construct them. All these solutions avoid the initialization-order-fiasco because the palettes get created at compile time.

My current favorite is the latter (gutting out the Qt containers in favor of std ones) because I don't think the implicit sharing is of much benefit here.

@daschuer
Copy link
Member

daschuer commented Aug 28, 2024

The ColorPalletes are currenrtly copied by value, which is a matter of three pointers due to Qt's implicit sharing.
A new ColorPalette class that has std:: container and a solution that avoids all the copies would be very welcome.
We actually need to have them only one time in memory. We need probabyl only a single copy, which used when editing the current pallette (one per use case). I have investigated it a bit but it tuns out to be quite bit of work so I have not done it (so be warned).
I hope I will find time to review this soon.

@@ -146,7 +146,9 @@ void ColorPaletteEditor::initialize(
m_resetPalette = paletteName;
QString saveName = paletteName;

for (const ColorPalette& palette : mixxx::PredefinedColorPalettes::kPalettes) {
const auto& kPalettes = mixxx::predefinedcolorpalettes::get();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A free get() function in a namespace looks weird. This is an indicator that the Namespace is an object.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

well, its effectively a singleton. So its up to interpretation whether it should be modeled as a class with a static member function or a namespace with a free function. they're basically equivalent, though I find the namespace more elegant.

kRekordboxHotcueColor16,
};

const static PredefinedColorPalettes kPalettes{
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Returning a local static is one way ti implement a singleton pattern. How about fully make use of that here?
as in a PredefinedColorPalettes::instance() function.

kTritKeyColor11,
kTritKeyColor12,
}},
.defaultHotcueColorPalette = kPalettes.mixxxHotcueColorPalette,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a deep copy. Can we avoid it?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can simply store a const ref because we know the object outlives the reference.

.defaultKeyColorPalette = kPalettes.mixxxKeyColorPalette,
.palettes{
// Hotcue Color Palettes
kPalettes.mixxxHotcueColorPalette,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This are also deep copies, which should be avoided.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The original were also deep copies though IIRC, but it should be easy to change.

@Swiftb0y
Copy link
Member Author

summarizing your review. there are two issues:

  1. implementation of the singleton.
    I personally prefer the namespace + free function because its simpler than wrapping both into a class. If there is a significant advantage of the class then I'm happy to change it. Can you think of one?
  2. deep copy of palettes.
    That was already the case previously, though it should be easy to change here if desired.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants